﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using AsyncLoggers.Exceptions;

namespace AsyncLoggers
{
    /// <summary>
    /// A shortcut for accessing some of the asynchronous
    /// logging functionality related to <see cref="TraceListener"/>-s
    /// </summary>
    public static class TraceAsyncLoggers
    {
        /// <summary>
        /// Swaps a synchronous trace listener for asynchronous one
        /// </summary>
        /// <exception cref="FailedToSwapLoggerException"></exception>
        public static void SwapTraceListenerForAsynchronous(string nameOfTraceListenerToBeSwapped)
        {
            for (int i = 0; i < Trace.Listeners.Count; i++)
            {
                TraceListener traceListener = Trace.Listeners[i];

                if (traceListener.Name.Equals(nameOfTraceListenerToBeSwapped, StringComparison.Ordinal) && !(traceListener is AsyncTraceListener))
                {
                    Trace.Listeners[i] = WrapTraceListener(traceListener);
                    return;
                }
            }

            throw new FailedToSwapLoggerException(
                "Swapping a TraceListener failed: found no synchronous trace listener named \"{0}\"".FormatWith(nameOfTraceListenerToBeSwapped));
        }

        /// <summary>
        /// Swaps all synchronous trace listeners for asynchronous ones
        /// </summary>
        public static void SwapAllTraceListenersForAsynchronous()
        {
            var updatedCollection = new List<TraceListener>();

            for (int i = 0; i < Trace.Listeners.Count; i++)
            {
                TraceListener traceListener = Trace.Listeners[i];

                if (traceListener is AsyncTraceListener)
                {
                    updatedCollection.Add(traceListener);
                    continue;
                }

                updatedCollection.Add(WrapTraceListener(traceListener));
            }

            Trace.Listeners.Clear();

            Trace.Listeners.AddRange(updatedCollection.ToArray());

            Trace.AutoFlush = false;
        }

        private static TraceListener WrapTraceListener(TraceListener traceListenerToWrap)
        {
            return new AsyncTraceListener(traceListenerToWrap)
                       {
                           Filter = traceListenerToWrap.Filter,
                           IndentLevel = traceListenerToWrap.IndentLevel,
                           IndentSize = traceListenerToWrap.IndentSize,
                           TraceOutputOptions = traceListenerToWrap.TraceOutputOptions
                       };
        }
    }
}